interface Request {
  type?: string;
  headers?: { [key: string]: string };
  params?: { [key: string]: string };
  body?: any;
  timeout?: number;
  getXhr?: (xhr: XMLHttpRequest) => void;
  responseType?: XMLHttpRequestResponseType;
  onprogress?: XMLHttpRequestEventTarget["onprogress"];
}

/**
 * 原生ajax
 * @param url
 * @param opt
 */
export function request(url: string, opt: Request) {
  const {
    type = "GET",
    headers,
    params,
    timeout = 10000000000,
    getXhr,
    responseType,
    body,
    onprogress,
  } = opt;
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    //处理search参数
    if (type === "GET" && params) {
      let __params = new URLSearchParams(params).toString();
      url += "?" + __params;
    }
    xhr.open(type, url);
    xhr.timeout = timeout;
    xhr.responseType = responseType || "";
    xhr.upload.onprogress = onprogress || null;
    if (headers) {
      for (let key in headers) {
        xhr.setRequestHeader(key, headers[key]);
      }
    }
    xhr.send(body);
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        const { responseURL, status, statusText, response } = xhr;
        switch (status) {
          case 0:
            return reject({ url: responseURL, status, statusText: "请求超时" });
          case 200:
          case 206:
            return resolve(response);
          default:
            return reject({ url: responseURL, status, statusText });
        }
      }
    };
    getXhr?.(xhr);
  });
}

/**
 * jsonp跨域 支持超时
 * @param url
 * @param opt
 */
export function jsonp(url: string, opt: Request) {
  return new Promise((resolve, reject) => {
    let { params, timeout = 5000 } = opt;
    const callback = "JSONP_CALLBACK_" + Date.now();
    const s = document.createElement("script");
    const body = document.getElementsByTagName("body")[0];
    let windowThis = window as any;
    windowThis[callback] = function (data: any) {
      resolve(data);
      body.removeChild(s);
      delete windowThis[callback];
      clearTimeout(timerId);
    };
    s.src += url + "?" + "callback=" + callback;
    s.async = true;
    if (params) {
      let arr = [];
      for (let key in params) arr.push(key + "=" + params[key]);
      s.src += "&" + arr.join("&");
    }
    body.appendChild(s);
    s.onerror = function (err) {
      reject(err);
      body.removeChild(s);
      delete windowThis[callback];
      clearTimeout(timerId);
    };
    const timerId = setTimeout(() => {
      resolve(`Request Timeout, By ${timeout / 1000}s`);
      body.removeChild(s);
      delete windowThis[callback];
      windowThis[callback] = function () {
        delete windowThis[callback];
      };
    }, timeout);
  });
}
